﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using Asistente.Model.IFPUG.MeasureUtilities;
using Asistente.Model.General;
using Asistente.Model.IFPUG;

namespace Asistente.Model.Representation
{
    public class Entity : DataGroup
    {
        public bool IsMaintained { get; set; }

        // Ifpug
        public int Dets { get; set; }
        public int Rets { get; set; }
        public bool OverwrittenMeasures { get; set; }

        [NonSerialized] private List<MasterDetail> masterDetailsRet;
        [XmlIgnore] public List<MasterDetail> MasterDetailRet { get { return masterDetailsRet; } }

        [NonSerialized]  private List<EditablePanel> panelDet;
        [XmlIgnore] public List<EditablePanel> PanelDet { get { return panelDet; } }

        private bool isChecked;
        public bool IsChecked { get { return isChecked; } set { isChecked = value; }  }
           
        #region IfpugModel Converter

        //La entidad se convierte aun Transformed entityel cual es agregado al modelo que se
        //esta generandoen la recorrida del modelo que ha generado el medidor.

        public IMeasurable ConvertToIfpugModel(IfpugModel ifpugModel)
        {
            masterDetailsRet = new List<MasterDetail>();
            panelDet = new List<EditablePanel>();

            //Crea el TransformedEntity
            var transformedEntity = new TransformedEntity
                                        {
                                           Entity = this,
                                           DataFunction = {Type = Identifier.Instance.Identify(this)}
                                        };

            //Se cuentan DET y RET
            transformedEntity.AddDet(GetDets(ifpugModel.App));
            transformedEntity.AddRet(GetRets(ifpugModel.App));   
         
            ifpugModel.Add(transformedEntity);
            return ifpugModel; 
        }

        //Se obtienen los dets que aporta la aplicacion a dicha entidad.
        private int GetRets(Application app)
        {
            if (OverwrittenMeasures)
            {
                return Rets;
            }

            //Como contar RET: 1 por defecto siempre
            //Debemos fijarnos si la entidad actua como master en un master detail, 
            // en caso de que asi sea, entonces sumamos un RET por cada uno de los
            // detalles.
            //En caso de que no actue en un master detail, entonces se cuenta un solo RET
            if (IsMaster(app))
            {
                return 1 + GetDetails(app);
            }
            return 1;
        }

        //Se obtienen los DETs que aporta la aplicacion a dicha entidad.
        //Para una entidad solamente aporan DET los controles de grid o form que no hayan sido contados.
        private int GetDets(Application app)
        {
            if (OverwrittenMeasures)
            {
                return Dets;
            }

            int dets = 0;

            List<String> countedControls = new List<String>();

            //Obtenemos todos los Grid y Form
            foreach (EditablePanel editablePanel in GetEditablePanels(app))
            {
                foreach (Control control in editablePanel.Controls)
                {
                    if (!countedControls.Contains(control.Name)) 
                        // Solo aportan dets controles no contados (osea con distinto nombre)
                    {
                        dets += ControlManager.Instance.GetDetDataFunction(control.ControlPattern) * control.Quantity;
                        countedControls.Add(control.Name);

                        //Agregamos el panel a la lista de paneles que aportan dets a la entidad
                        if(!panelDet.Contains(editablePanel)) 
                        { panelDet.Add(editablePanel);}
                    }
                }
            }
            return dets;
        }


        private int GetDetails(Application app)
        {
            int ret = 0;

            List<String> countedMasters = new List<String>();

            foreach (UseCase useCase in app.UseCases)
            {
                foreach (Screen screen in useCase.Screens)
                {
                    foreach (MasterDetail masterDetail in screen.MasterDetails)
                    {
                        //Se compara por el nombre debido a problema con desserializacion
                        if (masterDetail.Master.Entity != null && masterDetail.Master.Entity.Name.Equals(Name))
                        {
                            //La entidad actua como master en un master detail
                            // entonces se retornan tantos det como detalles
                            //solamente en caso de que no se hayan contado esos RET
                           
                            if (!countedMasters.Contains(masterDetail.Name))                            
                            {
                                ret = ret + masterDetail.Details.Count();
                                countedMasters.Add(masterDetail.Name);
                                
                                //Seagrega el master detail a la lista de masters detail que 
                                // aportan RETs a la entidad.
                                if (!masterDetailsRet.Contains(masterDetail))
                                { masterDetailsRet.Add(masterDetail); }
                            }
                            
                        }
                    }
                }
            }

            return ret;

        }

        //Return true si actua como master en al menos un MasterDetail
        private bool IsMaster(Application app)
        {
            return (from useCase in app.UseCases from screen in useCase.Screens from masterDetail in screen.MasterDetails select masterDetail).Any(masterDetail => masterDetail.Master != null && masterDetail.Master.Entity != null && masterDetail.Master.Entity.Name.Equals(this.Name));
        }

        //Obtener todos los paneles editables que trabajan sobre la entidad actual. No se retornan los Filter ya que no 
        //trabajan sobre entidades.
        private IEnumerable<EditablePanel> GetEditablePanels(Application app) 
        {
            List<Panel> allPanels = new List<Panel>();

            //Creamos la lista de todos los paneles y los master details
            foreach (UseCase useCase in app.UseCases)
            {
                foreach (Screen screen in useCase.Screens)
                {
                    //Agregamos los paneles de la screen
                    allPanels.AddRange(screen.Panels);

                    //Agregamos los panales de los master details
                    foreach (MasterDetail masterDetail in screen.MasterDetails)
                    {
                        if (masterDetail.Master != null) 
                        { 
                            allPanels.Add(masterDetail.Master);
                        }
                        allPanels.AddRange(masterDetail.Details);
                    }
                }
            }

            List<EditablePanel> editablePanels = new List<EditablePanel>();

            //Nos quedamos con los editables que trabajan sobre la entidadad
            foreach (Panel panel in allPanels)
            {
                //Es un editable panel y No es un Filter
                if (typeof(EditablePanel).IsAssignableFrom(panel.GetType()) && panel.GetType() != typeof(Filter))
                {   // Es editable panel
                    EditablePanel aux = panel as EditablePanel;

                    if (aux.Entity != null)
                    {
                        
                        if (aux.Entity.Name.Equals(this.Name))
                        { //Trabaja sobre la entidad actual
                            editablePanels.Add(aux);
                        }
                    }
                }
            }
            return editablePanels;
        }

        #endregion

        public  override string ToString()
        {
            StringBuilder content = new StringBuilder();
            content.AppendLine("Name: " + Name);

            if (OverwrittenMeasures) 
            {
                content.AppendLine("Has OverwrittenMeasuresIfpug enable");
                content.AppendLine("DET: " + Dets);
                content.AppendLine("RET: " + Rets);
            }
            
            return content.ToString();
        }
        
    }
}
